{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Student Grade Calculator using LangGraph\n",
    "\n",
    "This notebook illustrates the creation of a simple state-based graph with LangGraph to process student grades and produce detailed grade reports.\n",
    "\n",
    "## Overview\n",
    "\n",
    "The notebook includes:\n",
    "\n",
    "- Defining a structured state with TypedDict\n",
    "- Creating a node for grade calculation\n",
    "- Constructing and visualizing a LangGraph workflow\n",
    "- Processing student data and generating reports\n",
    "\n",
    "## Requirements\n",
    "\n",
    "```shell\n",
    "pip install langgraph typing ipython\n",
    "```\n",
    "\n",
    "## 1. Import Required Libraries\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import TypedDict, List\n",
    "from langgraph.graph import StateGraph\n",
    "from IPython.display import Image, display"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Define the State Structure\n",
    "\n",
    "We'll define a `StudentState` class using `TypedDict` to ensure type safety and provide a clear contract for the data flowing through our graph.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the state structure using TypedDict for type safety and clarity\n",
    "class StudentState(TypedDict):\n",
    "    \"\"\"\n",
    "    State schema that defines the structure of data flowing through the graph.\n",
    "    acts as a contract for what data each node can expect and modify.\n",
    "    \"\"\"\n",
    "\n",
    "    scores: List[float]  # List of numerical scores (e.g., test scores, assignment grades)\n",
    "    student_name: str  # Full name of the student\n",
    "    course_name: str  # Name of the course being graded\n",
    "    grade_report: str  # Final formatted grade report (generated by the node)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Create the Grade Calculation Function\n",
    "\n",
    "The function will serve as our main processing node. It takes student scores and generates a comprehensive grade report that includes:\n",
    "\n",
    "- Calculation of the average score\n",
    "- Assignment of letter grades based on the standard grading scale\n",
    "- Generation of a formatted report\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calculate_grade(state: StudentState) -> StudentState:\n",
    "    \"\"\"\n",
    "    Node function that processes student scores and generates a comprehensive grade report.\n",
    "\n",
    "    Args:\n",
    "        state (StudentState): Current state containing scores, student info, and course info\n",
    "\n",
    "    Returns:\n",
    "        StudentState: Updated state with the grade_report field populated\n",
    "\n",
    "    Note: In LangGraph, node functions receive the current state and return an updated state.\n",
    "    The framework automatically merges the returned state with the existing state.\n",
    "    \"\"\"\n",
    "    print(f\"Processing grades for: {state}\")\n",
    "\n",
    "    # Calculate the arithmetic mean of all scores\n",
    "    average_score = sum(state[\"scores\"]) / len(state[\"scores\"])\n",
    "\n",
    "    # Apply standard grading scale to determine letter grade uses a typical 10-point grading scale\n",
    "    if average_score >= 90:\n",
    "        letter_grade = \"A\"\n",
    "    elif average_score >= 80:\n",
    "        letter_grade = \"B\"\n",
    "    elif average_score >= 70:\n",
    "        letter_grade = \"C\"\n",
    "    elif average_score >= 60:\n",
    "        letter_grade = \"D\"\n",
    "    else:\n",
    "        letter_grade = \"F\"\n",
    "\n",
    "    # Generate a formatted report string with all relevant information modifies the state by adding the grade_report field\n",
    "    state[\"grade_report\"] = (\n",
    "        f\"Student: {state['student_name']}\\n\"\n",
    "        f\"Course: {state['course_name']}\\n\"\n",
    "        f\"Individual Scores: {', '.join(map(str, state['scores']))}\\n\"\n",
    "        f\"Average Score: {average_score:.2f}%\\n\"\n",
    "        f\"Final Grade: {letter_grade}\"\n",
    "    )\n",
    "\n",
    "    print(f\"Completed processing: {state['grade_report']}\")\n",
    "    return state"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Build the LangGraph Workflow\n",
    "\n",
    "Let's construct the state graph, integrate our grade calculation node, and compile it into a functional application.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "✅ Graph successfully compiled!\n"
     ]
    }
   ],
   "source": [
    "# Create the state graph using the defined state schema\n",
    "# StateGraph manages state transitions and ensures type safety\n",
    "graph = StateGraph(StudentState)\n",
    "\n",
    "graph.set_entry_point(\"grade_calculator\")  # node will be executed first\n",
    "\n",
    "# Add the grade calculation function as a node in the graph\n",
    "# The node name \"grade_calculator\" is an identifier for  processing step\n",
    "graph.add_node(\"grade_calculator\", calculate_grade)\n",
    "\n",
    "# Define the graph flow: set entry and exit points\n",
    "graph.set_finish_point(\"grade_calculator\")  # node marks the end of processing\n",
    "\n",
    "# Compile the graph into an executable application\n",
    "# step validates the graph structure and prepares it for execution\n",
    "app = graph.compile()\n",
    "\n",
    "print(\"✅ Graph successfully compiled!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Visualize the Graph Structure\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# The mermaid format creates flowchart-style diagrams\n",
    "display(Image(app.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Save Graph Visualizations (Optional)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "📁 Graph visualizations saved to output/ directory\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "# Create output directory if it doesn't exist\n",
    "os.makedirs(\"output\", exist_ok=True)\n",
    "\n",
    "# Save the graph visualization as a PNG file for documentation purposes\n",
    "with open(\"output/04-Multiple_Inputs.png\", \"wb\") as f:\n",
    "    f.write(app.get_graph().draw_mermaid_png())\n",
    "\n",
    "# Save the raw Mermaid diagram code for potential reuse or modification\n",
    "# Mermaid is a popular diagramming syntax that can be rendered in many tools\n",
    "with open(\"output/04-Multiple_Inputs.mmd\", \"w\") as f:\n",
    "    f.write(app.get_graph().draw_mermaid())\n",
    "\n",
    "print(\"📁 Graph visualizations saved to output/ directory\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Execute the Graph with Sample Data\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Processing grades for: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'scores'</span>: <span style=\"font-weight: bold\">[</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">88.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">92.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">85.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">94.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">87.5</span><span style=\"font-weight: bold\">]</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'student_name'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'Alice Johnson'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'course_name'</span>: \n",
       "<span style=\"color: #008000; text-decoration-color: #008000\">'Python Programming'</span><span style=\"font-weight: bold\">}</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Processing grades for: \u001b[1m{\u001b[0m\u001b[32m'scores'\u001b[0m: \u001b[1m[\u001b[0m\u001b[1;36m88.5\u001b[0m, \u001b[1;36m92.0\u001b[0m, \u001b[1;36m85.5\u001b[0m, \u001b[1;36m94.0\u001b[0m, \u001b[1;36m87.5\u001b[0m\u001b[1m]\u001b[0m, \u001b[32m'student_name'\u001b[0m: \u001b[32m'Alice Johnson'\u001b[0m, \u001b[32m'course_name'\u001b[0m: \n",
       "\u001b[32m'Python Programming'\u001b[0m\u001b[1m}\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Completed processing: Student: Alice Johnson\n",
       "Course: Python Programming\n",
       "Individual Scores: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">88.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">92.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">85.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">94.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">87.5</span>\n",
       "Average Score: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">89.50</span>%\n",
       "Final Grade: B\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Completed processing: Student: Alice Johnson\n",
       "Course: Python Programming\n",
       "Individual Scores: \u001b[1;36m88.5\u001b[0m, \u001b[1;36m92.0\u001b[0m, \u001b[1;36m85.5\u001b[0m, \u001b[1;36m94.0\u001b[0m, \u001b[1;36m87.5\u001b[0m\n",
       "Average Score: \u001b[1;36m89.50\u001b[0m%\n",
       "Final Grade: B\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "🎯 Graph execution completed!\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n",
       "🎯 Graph execution completed!\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from rich import print\n",
    "\n",
    "# The invoke method runs the entire graph pipeline with the provided input state\n",
    "result = app.invoke(\n",
    "    {\n",
    "        \"scores\": [88.5, 92.0, 85.5, 94.0, 87.5],  # Sample test scores\n",
    "        \"student_name\": \"Alice Johnson\",  # Student identifier\n",
    "        \"course_name\": \"Python Programming\",  # Course context\n",
    "        # Note: grade_report will be generated by the calculate_grade node\n",
    "    }\n",
    ")\n",
    "\n",
    "print(\"\\n🎯 Graph execution completed!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. Display the Final Grade Report\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">📊 FINAL GRADE REPORT:\n",
       "</pre>\n"
      ],
      "text/plain": [
       "📊 FINAL GRADE REPORT:\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">==================================================\n",
       "</pre>\n"
      ],
      "text/plain": [
       "==================================================\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Student: Alice Johnson\n",
       "Course: Python Programming\n",
       "Individual Scores: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">88.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">92.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">85.5</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">94.0</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">87.5</span>\n",
       "Average Score: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">89.50</span>%\n",
       "Final Grade: B\n",
       "</pre>\n"
      ],
      "text/plain": [
       "Student: Alice Johnson\n",
       "Course: Python Programming\n",
       "Individual Scores: \u001b[1;36m88.5\u001b[0m, \u001b[1;36m92.0\u001b[0m, \u001b[1;36m85.5\u001b[0m, \u001b[1;36m94.0\u001b[0m, \u001b[1;36m87.5\u001b[0m\n",
       "Average Score: \u001b[1;36m89.50\u001b[0m%\n",
       "Final Grade: B\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">==================================================\n",
       "</pre>\n"
      ],
      "text/plain": [
       "==================================================\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "print(\"📊 FINAL GRADE REPORT:\")\n",
    "print(\"=\" * 50)\n",
    "print(result[\"grade_report\"])\n",
    "print(\"=\" * 50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py312",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
